#include "Smoke.h"
#include <ctime>



PSSmoke::PSSmoke() :	 bActive(0), bDiscard(0), bFirstRun(true), time(0.0f), g_device(0), g_context(0), srv_noise_texture(0), 
						 srv_fire_texture(0), vb_init(0),vb_elements(0), vb_elements_2(0), IA_Smoke(0)
{
	
}

PSSmoke::~PSSmoke()
{
	try
	{
		if (g_device)
			g_device->Release();
		if (g_context)
			g_context->Release();
		if (srv_noise_texture)
			srv_noise_texture->Release();
		if (srv_fire_texture)
			srv_fire_texture->Release();
		if (vb_elements)
			vb_elements->Release();
		if (vb_elements_2)
			vb_elements_2->Release();
		if (vb_init)
			vb_init->Release();
		if (IA_Smoke)
			IA_Smoke->Release();
	}
	catch(...)
	{
		MessageBoxA(0, "exception thrown in  destructor", 0, 0);
	}
}


void PSSmoke::Update(float dt)
{
	
}

void PSSmoke::draw(CXMMATRIX mVP, const XMFLOAT4& pos, float dt)
{
#ifndef PIX

	if (!bActive)
		return;

	time += dt;

	UINT stride = sizeof(Particle);
	UINT offset = 0;
	ID3DX11EffectTechnique* tech;
	ID3D11Buffer* buff_empty[1] =  {0};
	ID3D11InputLayout* current_IA;
	D3D11_PRIMITIVE_TOPOLOGY current_primitive_topology;

	// Save state
		
	g_context->IAGetInputLayout(&current_IA);
	g_context->IAGetPrimitiveTopology(&current_primitive_topology);
	//////////////////////////////////////////////////////////////////////////


	// Set Topology
	g_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
	
	// set input layout 
	g_context->IASetInputLayout(IA_Smoke);



		
	// Swap buffers' addresses
	if (!bFirstRun) {
		ID3D11Buffer* tmp;
		tmp = vb_elements;
		vb_elements = vb_elements_2;
		vb_elements_2 = tmp;
	}
	
	//////////////////////////////////////////////////////////////////////////

	
	// First Pass : update leafElements - stream out 

	// Set effect Variables
	ID3DX11EffectMatrixVariable* fx_m_WVP;
	ID3DX11EffectShaderResourceVariable* fx_noise_texture;

	fx_m_WVP = m_fx->GetVariableByName("m_WVP")->AsMatrix();
	//fx_m_WVP->SetMatrix((float*)&mWVP);
		
	fx_noise_texture = m_fx->GetVariableByName("noise_texture")->AsShaderResource();
	fx_noise_texture->SetResource(srv_noise_texture);

			
	ID3DX11EffectScalarVariable*  fx_bDiscard = m_fx->GetVariableByName("bDiscard")->AsScalar();
	fx_bDiscard->SetBool(bDiscard);

	ID3DX11EffectScalarVariable*  fx_time = m_fx->GetVariableByName("time")->AsScalar();
	fx_time->SetFloat(time);

	ID3DX11EffectScalarVariable*  fx_dt = m_fx->GetVariableByName("dt")->AsScalar();
	fx_dt->SetFloat(dt);

	ID3DX11EffectVectorVariable*   fx_vPosition = m_fx->GetVariableByName("vPosition")->AsVector();
	fx_vPosition->SetFloatVector((float*)&m_position);

	// Get technique - Draw()
	tech = m_fx->GetTechniqueByName("Smoke_SO");
	tech->GetPassByIndex(0)->Apply(0, g_context);
	


	if (bFirstRun) 
	{
		g_context->IASetVertexBuffers(0, 1, &vb_init, &stride, &offset);
		// Set Stream-Out Buffer
		g_context->SOSetTargets(1, &vb_elements_2, &offset);	
		g_context->Draw(1, 0);
		bFirstRun = false;
	}
	else
	{
		g_context->IASetVertexBuffers(0, 1, &vb_elements, &stride, &offset);
		// Set Stream-Out Buffer
		g_context->SOSetTargets(1, &vb_elements_2, &offset);	
		g_context->DrawAuto();
	}


	// Un-bind Stream-Out Buffer
	g_context->SOSetTargets(1, buff_empty, &offset);
		
	
	///////////////////////////////////////////////////////////


	// Second Pass : particles to trianglelist	
	
	// Set Vertex Buffer
	g_context->IASetVertexBuffers(0, 1, &vb_elements_2, &stride, &offset);
	
	// Set Stream-Out Buffer
	g_context->SOSetTargets(1, &vb_elements, &offset);	


	// Variables
	ID3DX11EffectShaderResourceVariable* fx_tex = m_fx->GetVariableByName("tex")->AsShaderResource();
	fx_tex->SetResource(srv_fire_texture);

	ID3DX11EffectVectorVariable* fx_p_eye_pos = m_fx->GetVariableByName("p_eye_pos")->AsVector();
	ID3DX11EffectMatrixVariable* fx_m_VP = m_fx->GetVariableByName("m_VP")->AsMatrix();

	fx_p_eye_pos->SetFloatVector((float*)&pos);
	fx_m_VP->SetMatrix((float*)&mVP);

	// Get Technique - Draw()
	tech = m_fx->GetTechniqueByName("Smoke_SO_Draw");
	tech->GetPassByIndex(0)->Apply(0, g_context);
	
	// draw geometry info
	g_context->DrawAuto();


	// Un-bind Stream-Out Buffer
	g_context->SOSetTargets(1, buff_empty, &offset);


	// Restore state
	g_context->OMSetBlendState(0, 0, 0xffffffff);
	g_context->RSSetState(0);
	g_context->OMSetDepthStencilState(0, 0);

	g_context->IASetPrimitiveTopology(current_primitive_topology);
	if (current_IA) {
		g_context->IASetInputLayout(current_IA);
		current_IA->Release();
	}



#endif
	
}

void PSSmoke::init(ID3D11Device* g_dev, ID3D11DeviceContext* g_ctx, ID3DX11Effect* fx)
{
	
	g_device = g_dev;
	g_device->AddRef();

	g_context = g_ctx;
	g_ctx->AddRef();

	m_fx = fx;
	m_fx->AddRef();


	// Input layout - Fire IA
	D3D11_INPUT_ELEMENT_DESC leaf_layout[] = {
		{ "POSITION", 0,  DXGI_FORMAT_R32G32B32A32_FLOAT,    0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "DIRECTION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,    0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "PARAMS", 0,    DXGI_FORMAT_R32G32B32A32_FLOAT   , 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	D3DX11_PASS_DESC passDesc;
	ID3DX11EffectTechnique* tech = m_fx->GetTechniqueByName("Smoke_SO");
	tech->GetPassByIndex(0)->GetDesc(&passDesc);

	HRESULT hr = g_device->CreateInputLayout(leaf_layout, 3, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &IA_Smoke);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating IA fire", 0, 0);
	////////////////////////////////////////////////////////////////

	// Buffers - Init buffer
	D3D11_BUFFER_DESC vb_desc;
	vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vb_desc.ByteWidth = sizeof(Particle);
	vb_desc.CPUAccessFlags = vb_desc.MiscFlags = 0;
	vb_desc.StructureByteStride = 0;
	vb_desc.Usage = D3D11_USAGE_DEFAULT;

	Particle p[5];

	for (int i=0; i<5; i++)
	{
		p[0].pos = XMFLOAT4(0.0f, 0.0f, -0.0f, 1.0f);
		p[0].direction = XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);
		p[0].params.x = PSSmoke::SMOKE_GENERATOR;
		p[0].params.y = 0.0f;
		p[0].params.z = p[0].params.w = 0.0f;
	}

	D3D11_SUBRESOURCE_DATA vb_data;
	vb_data.pSysMem = p;
	vb_data.SysMemPitch = vb_data.SysMemSlicePitch = 0;

	hr = g_device->CreateBuffer(&vb_desc, &vb_data, &vb_init);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating leaves init buffer", 0, 0);

	//////////////////////////////

	vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
	vb_desc.ByteWidth = sizeof(Particle) * MAX_ELEMENTS;

	hr = g_device->CreateBuffer(&vb_desc, 0, &vb_elements);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating fire buffer", 0, 0);

	hr = g_device->CreateBuffer(&vb_desc, 0, &vb_elements_2);
	if (FAILED(hr))
		MessageBoxA(0, "Error creating fire buffer 2", 0, 0);
	///////////////////////////////

	// Textures
	hr = D3DX11CreateShaderResourceViewFromFile(g_device, L"..\\ACW_08968\\media\\noise_texture.jpg", NULL, NULL, &srv_noise_texture, 0);
	if (FAILED(hr))
		MessageBoxA(0, "Error create noise texture SRV", 0, 0);

	hr = D3DX11CreateShaderResourceViewFromFile(g_device, L"..\\ACW_08968\\media\\smoke.png", NULL, NULL, &srv_fire_texture, 0);
	if (FAILED(hr))
		MessageBoxA(0, "Error create fire texture SRV", 0, 0);
	
	
}



void PSSmoke::setPosition(float x, float y, float z)
{
	m_position.x = x;
	m_position.y = y;
	m_position.z = z;
}


void PSSmoke::setPosition(XMFLOAT3 p)
{
	m_position = p;
}